package resource

import (
	"flare-admin/db/dao"
	"flare-admin/ecode"
	"flare-admin/http/model"
	"flare-admin/http/model/k8sresource"
	"flare-admin/service/dto/k8s"
	"flare-admin/service/external/k8s/clientset"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"gopkg.in/yaml.v3"
	corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type PodService struct {
	dao *dao.DBTXQuery
}

// ListPods 列出指定集群中的所有Pod, clusterKet使用clientset包中的BuildClusterKey方法生成, namespace = ""表示所有命名空间
func (s *PodService) ListPods(ctx *gin.Context, csKey string, namespace string, kubeconfig []byte) ([]k8sresource.PodInfo, error) {
	cs, err := clientset.GetClientset(csKey)
	if err != nil {
		if _, err = clientset.AddClientsetFromBytesByKey(csKey, kubeconfig); err != nil {
			logrus.Errorf("[ListPods] - 无法获取集群 %s 的Clientset: %v", csKey, err)
			return nil, err
		}
	}
	cs, err = clientset.GetClientset(csKey)
	if err != nil {
		return nil, ecode.ErrClusterNotExists
	}
	list, err := cs.CoreV1().Pods(namespace).List(ctx, v1.ListOptions{})
	if err != nil {
		return nil, ecode.ErrClusterResourceFetching
	}

	podInfoList := make([]k8sresource.PodInfo, 0, len(list.Items))
	for _, pod := range list.Items {
		model := k8s.TransferPodToPodModel(&pod)
		podInfoList = append(podInfoList, *model)
	}
	return podInfoList, nil
}

func (s *PodService) ListPodsByClusterID(ctx *gin.Context, clusterID string, namespace string) ([]k8sresource.PodInfo, error) {
	id, err := strconv.ParseInt(clusterID, 10, 32)
	if err != nil {
		return nil, ecode.ErrRequestParam
	}
	clusterInfo, err := s.dao.Cluster.SelectSingleClusterConfigByID(ctx, int32(id))
	if err != nil {
		if ecode.IsBizError(err) {
			return nil, err
		}
		return nil, ecode.ErrClusterNotExists
	}
	return s.ListPods(ctx, clientset.BuildMapKey(clusterInfo.ClusterType, clusterInfo.Name), namespace, []byte(clusterInfo.Kubeconfig))
}

func (s *PodService) CreatePodInClusterID(ctx *gin.Context, clusterID int, namespace string, pod k8sresource.PodInfo) (string, error) {

	clusterInfo, err := s.dao.Cluster.SelectSingleClusterConfigByID(ctx, int32(clusterID))
	if err != nil {
		logrus.Errorf("[CreatePodInClusterID] - [SelectSingleClusterConfigByID] - failed to select cluster config by ID: %v", err)
		return "", err
	}
	cs, err := clientset.GetClientset(clientset.BuildMapKey(clusterInfo.ClusterType, clusterInfo.Name))
	if err != nil {
		logrus.Error("[CreatePodInClusterID] - [GetClientset] - failed to get clientset: %v", err)
		return "", ecode.ErrClusterNotExists
	}
	k8sPod := k8s.TransferPodModelToPod(&pod)
	_, err = cs.CoreV1().Pods(namespace).Create(ctx, k8sPod, v1.CreateOptions{})
	if err != nil {
		logrus.Errorf("[CreatePodInClusterID] - [Create] - failed to create pod in cluster %s: %v", clusterInfo.Name, err)
		return "", ecode.ErrCreateResource
	}
	return k8sPod.Name, nil
}

func (s *PodService) CreatePodByYaml(ctx *gin.Context, clusterID int, yamlContent string) (string, error) {
	// 1. 获取集群信息
	clusterInfo, err := s.dao.Cluster.SelectSingleClusterConfigByID(ctx, int32(clusterID))
	if err != nil {
		logrus.Errorf("[CreatePodByYaml] - [SelectSingleClusterConfigByID] - failed to select cluster config by ID %d: %v", clusterID, err)
		return "", err
	}

	// 2. 获取clientset
	cs, err := clientset.GetClientset(clientset.BuildMapKey(clusterInfo.ClusterType, clusterInfo.Name))
	if err != nil {
		logrus.Errorf("[CreatePodByYaml] - [GetClientset] - failed to get clientset for cluster %s of type %s: %v", clusterInfo.Name, clusterInfo.ClusterType, err)
		return "", ecode.ErrClusterNotExists
	}

	// 3. 创建Pod
	// 3.1 反序列化yaml为pod
	p := corev1.Pod{}
	if err = yaml.Unmarshal([]byte(yamlContent), &p); err != nil {
		logrus.Errorf("[CreatePodByYaml] - [Unmarshal] - failed to unmarshal YAML content: %v", err)
		return "", ecode.ErrCreateResource
	}

	_, err = cs.CoreV1().Pods(p.Namespace).Create(ctx, &p, v1.CreateOptions{})
	if err != nil {
		logrus.Errorf("[CreatePodByYaml] - [CreatePodFromYaml] - failed to create pod from YAML in cluster %s: %v", clusterInfo.Name, err)
		return "", ecode.ErrCreateResource
	}
	return model.SuccessMessage, nil
}
